package pers.zb.center.web.boss.handler;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import pers.zb.center.common.core.util.DateUtil;
import pers.zb.center.common.core.util.StringUtil;
import pers.zb.center.common.core.vo.AjaxResult;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.util.Date;

@EnableWebMvc
@ControllerAdvice
public class WebExceptionHandler {

    Logger logger = Logger.getLogger(WebExceptionHandler.class);

    /*
     * 请求接口权限认证不通过的异常捕捉
     *
     * UnauthorizedException：表示请求无权限或者无角色，认证不通过
     * 如果抛出UnauthorizedException，将被该异常处理器截获来显示没有权限信息
     *
     * //@ResponseStatus(HttpStatus.UNAUTHORIZED)
     */
    @ExceptionHandler({UnauthorizedException.class})
    public String unauthenticatedException(UnauthorizedException e,HttpServletRequest request,HttpServletResponse response) throws Exception{
        String requestedWith = request.getHeader("X-Requested-With");
        if (StringUtils.isNotEmpty(requestedWith) && StringUtils.equals(requestedWith, "XMLHttpRequest")) {//如果是ajax请求，则返回json数据给前端，友好提示。
            PrintWriter out = response.getWriter();
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json");
            out.write(JSONObject.toJSONString(new AjaxResult<String>(500,"抱歉！您没有足够的权限执行该操作！")));
            if(null != out){
                out.flush();
                out.close();
            }
            return null;
        } else {//不是ajax请求，进行重定向到权限错误页面
            request.setAttribute("errorMsg", "抱歉！您没有足够的权限执行该操作！");
        }
        return "/common/exception/unauthorized";
    }

    /**
     * 代码运行时异常的捕捉
     * @Title: operateExp
     * @Description: 全局异常控制，记录日志
     * 任何一个方法发生异常，一定会被这个方法拦截到。然后，输出日志。封装Map并返回给页面显示错误信息：
     * 特别注意：返回给页面错误信息只在开发时才使用，上线后，要把错误页面去掉，只打印log日志即可，防止信息外漏
     * @param: @param ex
     * @param: @param request
     * @return: String
     * @throws:
     */
    @ExceptionHandler(RuntimeException.class)
    public String operateExp(RuntimeException ex, HttpServletRequest request,HttpServletResponse response) throws Exception{
        logger.error(ex.getMessage(), ex);
        logger.info("************* ------ RuntimeException异常信息已记录（" + DateUtil.getDateTimeFormat(new Date()) + "） ------- ***********");

        String requestedWith = request.getHeader("X-Requested-With");
        if (StringUtils.isNotEmpty(requestedWith) && StringUtils.equals(requestedWith, "XMLHttpRequest")) {//如果是ajax请求，则返回json数据给前端，友好提示。
            PrintWriter out = response.getWriter();
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json");
            out.write(JSONObject.toJSONString(new AjaxResult<String>(500,"哎呀！系统出现了错误，管理员收到通知后会尽快修复哦！")));
            if(null != out){
                out.flush();
                out.close();
            }
            return null;
        } else {//不是ajax请求，进行重定向到权限错误页面
            request.setAttribute("errorMsg", "哎呀！系统出现了错误，管理员收到通知后会尽快修复哦！");
        }
        return "/common/exception/error";
    }

    /**
     * ajax请求异常的捕捉
     * @param ex
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @ExceptionHandler(AjaxException.class)
    @ResponseBody
    public AjaxResult<String> operateExpAjax(AjaxException ex, HttpServletRequest request,HttpServletResponse response) throws Exception {
        logger.error(ex.getMessage(), ex);
        logger.info("************* ------ AjaxException异常信息已记录（" + DateUtil.getDateTimeFormat(new Date()) + "） ------- ***********");

        AjaxResult<String> ajaxResult = new AjaxResult<String>();
        if(StringUtil.isBlank(ex.getMessage()) == false){
            String message = ex.getMessage();
            String[] msgArr = message.split("#");
            if(msgArr.length > 1){//说明传递了错误码。例如：throw new AjaxException("系统异常#10000");
                ajaxResult.setCode(Integer.parseInt(msgArr[0]));
                ajaxResult.setMsg(msgArr[1]);
            }else{//没有传递错误码，而是字符串错误信息
                ajaxResult.setCode(500);//默认500错误码
                ajaxResult.setMsg(ex.getMessage());//自定义的异常错误信息
            }
        }else{//如果是一个空信息的异常，例如 throw new AjaxException();
            ajaxResult.setCode(500);//默认500错误码
            ajaxResult.setMsg("哎呀！系统出现了错误，管理员收到通知后会尽快修复哦！");
        }
        return ajaxResult;
    }


    /**
     * 网络连接出现异常的捕捉
     * @param ex
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @ExceptionHandler(ConnectException.class)
    public String operateExpNetException(ConnectException ex, HttpServletRequest request,HttpServletResponse response) throws Exception {
        logger.error(ex.getMessage(), ex);
        logger.info("************* ------ ConnectException异常信息已记录（" + DateUtil.getDateTimeFormat(new Date()) + "） ------- ***********");

        String requestedWith = request.getHeader("X-Requested-With");
        if (StringUtils.isNotEmpty(requestedWith) && StringUtils.equals(requestedWith, "XMLHttpRequest")) {//如果是ajax请求，则返回json数据给前端，友好提示。
            PrintWriter out = response.getWriter();
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json");
            out.write(JSONObject.toJSONString(new AjaxResult<String>(500,"哎呀！网路连接错误，请稍后重试哟！")));
            if(null != out){
                out.flush();
                out.close();
            }
            return null;
        } else {//不是ajax请求，进行重定向到权限错误页面
            request.setAttribute("errorMsg", "哎呀！网路连接错误，请稍后重试哟！");
        }
        //将Ajax异常信息回写到前台，用于页面的提示
        return "/common/exception/error";
    }
}